package cn.hcbycloud.common.jwt.service.jwt.impl;


import cn.hcbycloud.common.core.constant.CommonConstant;
import cn.hcbycloud.common.core.constant.TokenExpireDayType;
import cn.hcbycloud.common.core.exception.CustomizeException;
import cn.hcbycloud.common.jwt.service.encryptionkey.BaseGenerateJwtKeyService;
import cn.hcbycloud.common.jwt.service.jwt.JwtBuilderFactory;
import cn.hcbycloud.common.jwt.service.jwt.JwtService;
import cn.hcbycloud.common.jwt.vo.JwtToken;
import cn.hcbycloud.common.jwt.vo.LoginInfo;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;

/**
 * @author gaoh
 * @desc JWT相关服务接口实现
 * @date 2022年01月12日 下午 11:35
 */
@Slf4j
public class JwtServiceImpl implements JwtService {

    @Override
    public JwtToken generateToken(LoginInfo loginInfo, BaseGenerateJwtKeyService generateJwtKeyService, JwtBuilderFactory jwtFactory) {
        // 判断用户相关信息是否为null
        if (ObjectUtil.isNull(loginInfo)) {
            log.error("生成token的登录对象信息为空");
            throw new CustomizeException("登录信息为空，无法生成Token");
        }
        // 获取JWT builder
        JwtToken jwtToken = jwtFactory.getJwtToken();
        // 获取JWT 失效天数
        Integer expireDays = jwtToken.getBuilderExpireDay();
        // 超时时间为null or 小于等于0
        if (ObjectUtil.isNull(expireDays) || expireDays <= 0) {
            jwtToken.setBuilderExpireDay(TokenExpireDayType.TOKEN_EXPIRE_DAY_TYPE_1D_5D_DEFAULT.getTokenSelfExpireDay());
        }
        String tokenType = jwtToken.getTokenType();
        if(StrUtil.isBlank(tokenType)) {
            throw new CustomizeException("token认证类型为空，无法生成Token");
        }
        loginInfo.setLoginType(tokenType);
        // 计算超时时间
        Date expireDate= DateUtil.offset(new Date(), DateField.DAY_OF_YEAR,jwtToken.getBuilderExpireDay());
        String token = Jwts.builder()
                // jwt payload --> KV
                .claim(CommonConstant.JWT_LOGIN_INFO_KEY, JSON.toJSONString(loginInfo))
                // jwt id
                .setId(RandomUtil.randomString(15))
                // jwt 过期时间
                .setExpiration(expireDate)
                // jwt 签名 --> 加密
                .signWith(generateJwtKeyService.getPrivateKey(), SignatureAlgorithm.RS256)
                .compact();

        return new JwtToken(token, jwtToken.getTokenType(), expireDays);
    }

    @Override
    public LoginInfo getLoginInfoToken(String tokenStr, BaseGenerateJwtKeyService generateJwtKeyService) {
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(generateJwtKeyService.getPublicKey())
                .parseClaimsJws(tokenStr);
        Claims body = claimsJws.getBody();
        String loginInfoStr = body.get(CommonConstant.JWT_LOGIN_INFO_KEY).toString();
        LoginInfo loginInfo = JSON.parseObject(body.get(CommonConstant.JWT_LOGIN_INFO_KEY).toString(), LoginInfo.class);
        return loginInfo;
    }

    @Override
    public void verifierToken(String tokenStr, BaseGenerateJwtKeyService generateJwtKeyService) {
        this.getLoginInfoToken(tokenStr, generateJwtKeyService);
    }
}